package cz.fit.dpo.task1;

import java.util.ArrayList;
import java.util.List;

import cz.fit.dpo.task1.exceptions.ItemNotOwnedException;
import cz.fit.dpo.task1.exceptions.RoomsAreNotNeighboursException;
import cz.fit.dpo.task1.utils.Tuple;

/**
 * class for representing this game
 */
public class Game {

	/**
	 * player of this game
	 */
	Player player;

	/**
	 * rooms in this game
	 */
	List<Room> rooms;

	/**
	 * items in this game
	 */
	List<Item> items;

	/**
	 * winning state of this game
	 */
	Winner winningState;
	
	/**
	 * world of this game
	 */
	World world;
	
	/**
	 * constructs this game from a given world
	 */
	public Game (World world) {
		this.world = world;
		player = new Player ();
		makeRoomNet();
		placeItems();
		setPlayerPosition();
		setWinningConditions();
	}
	
	/**
	 * adds rooms and doors
	 */
	public void makeRoomNet () {
		rooms = new ArrayList<Room>(world.getRooms().size());
		for ( String room : world.getRooms() ) {
			rooms.add (new Room (room));
		}
		Room tempRoom1;
		Room tempRoom2;
		for ( Tuple<String, String> doors : world.getDoors() ) {
			tempRoom1 = findRoom ( doors.getItem1() );
			tempRoom2 = findRoom ( doors.getItem2() );
			tempRoom1.addNeighbouringRoom(tempRoom2);
			tempRoom2.addNeighbouringRoom(tempRoom1);
		}		
	}
	
	/**
	 * adds items
	 */
	public void placeItems () {
		items = new ArrayList<Item>(world.getItems().size());
		Room tempRoom;
		String itemName;
		boolean movable;
		Item tempItem;
		for ( Tuple<String, String> itemAndLocation : world.getItems() ) {
			tempRoom = findRoom (itemAndLocation.getItem2());
			itemName = itemAndLocation.getItem1();
			movable = true;
			if ( itemName.indexOf(World.UNMOVABLE) != -1 ) {
				movable = false;
				itemName.replace(World.UNMOVABLE, "");
			}
			tempItem = new Item (itemName, movable);
			items.add(tempItem);
			tempRoom.addOwnedItem(tempItem);
		} 
	}
	
	/**
	 * places the player
	 */
	public void setPlayerPosition () {
		player.moveToRoom(findRoom (world.getPlayerStartsIn()));
	}
	
	/**
	 * sets winning state
	 */
	public void setWinningConditions () {
		winningState = new Winner();
		for ( String condition : world.getWinningConditions() ) {
			int index;
			index = condition.indexOf(" ");
			String who = condition.substring(0, index);
			condition = condition.substring(index + 1);
			index = condition.indexOf(" ");
			String what = condition.substring(0, index);
			condition = condition.substring(index + 1);
			if ( who.compareTo("player") == 0 ) {
				winningState.addCondition ( what, condition, this );
			}
		}
	}
	
	/**
	 * tries to move player from one room to another
	 */
	public boolean movePlayer (Room toBeNewRoom) throws RoomsAreNotNeighboursException {
		if (player.isInRoom().isNeighbour(toBeNewRoom)) {
			if (player.canMove(toBeNewRoom) && toBeNewRoom.isOpen(player)) {
				player.moveToRoom(toBeNewRoom);
				return true;
			}
			return false;
		}
		throw new RoomsAreNotNeighboursException ();
	}
	
	/**
	 * tries to put item from room where the player currently is to his bag
	 */
	public boolean liftItem (Item toBeLiftedItem) throws ItemNotOwnedException {
		if (player.isInRoom().owns(toBeLiftedItem)) {
			if (player.isInRoom().canRemoveItem(toBeLiftedItem) && player.canLift(toBeLiftedItem)) {
				player.isInRoom().removeOwnedItem(toBeLiftedItem);
				player.lift(toBeLiftedItem);
				return true;
			}
			return false;
		}
		throw new ItemNotOwnedException ();
	}
	
	/**
	 * tries to put item from player's bag to room he's currently in
	 */
	public boolean dropItem (Item toBeDroppedItem) throws ItemNotOwnedException {
		if ( player.owns(toBeDroppedItem) ) {
			if (player.isInRoom().canAddItem(toBeDroppedItem) && player.canDrop(toBeDroppedItem)) {
				player.drop(toBeDroppedItem);
				player.isInRoom().addOwnedItem(toBeDroppedItem);
				return true;
			}
			return false;
		}
		throw new ItemNotOwnedException ();
	}
	
	/**
	 * finds a room according to given name
	 */
	public Room findRoom (String name) {
		Room room = null;
		for ( Room aRoom : rooms ) {
			if ( aRoom.getName ().equals(name) ) {
				room = aRoom;
				break;
			}
		}
		return room;
	}	
	
	/**
	 * finds an item according to given name
	 */
	public Item findItem (String name) {
		Item item = null;
		for ( Item anItem : items ) {
			if ( anItem.getName ().equals(name) ) {
				item = anItem;
				break;
			}
		}
		return item;
	}

	/**
	 * gets the player
	 */
	public Player getPlayer() {
		return player;
	}

	/**
	 * gets the rooms
	 */
	public List<Room> getRooms() {
		return rooms;
	}

	/**
	 * gets the world
	 */
	public World getWorld() {
		return world;
	}

	/**
	 * gets the items
	 */
	public List<Item> getItems() {
		return items;
	}

	/**
	 * gets the winning state
	 */
	public Winner getWinningState() {
		return winningState;
	}
	
	/**
	 * did the player win?
	 */
	public boolean isVictory () {
		if ( !player.isInRoom().equals(winningState.isInRoom()) ){
			return false;
		}
		for (Item winningItem : winningState.getOwnedItems()) {
			if ( !player.getOwnedItems().contains(winningItem) ){
				return false;
			}
		}
		for (Room winningRoom : winningState.getVisitedRooms()) {
			if ( !player.getVisitedRooms().contains(winningRoom) ){
				return false;
			}
		}
		return true;
	}
	
}
